home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power Programmierung
/
Power-Programmierung (Tewi)(1994).iso
/
magazine
/
drdobbs
/
ddjcompr
/
hstest
/
src
/
huffp.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-04-28
|
20KB
|
888 lines
#include "stdio.h"
#include "fcntl.h"
#include "tomlib.h"
#include "setjmp.h"
#include "pq.h"
#include "huffman.h"
#include "pack.h"
#define STATIC
#define MIN_LENGTH 3 /* minimum to be compressed */
#define MAXCODELENGTH 0x0f
#define SENDLEN 0xfff /* MUST BE 00001111111 */
typedef unsigned char uchar;
typedef unsigned short uint;
jmp_buf bit_to_long = {0};
void *ck_alloc(unsigned int len)
{
void *calloc(),*s;
if ((s = calloc(len,1)) == NULL)
panic("can't allocate memory");
}
STATIC uint ln2(register uint charset)
{
register int ln;
for (ln = 0; charset > 1; charset >>= 1)
ln++;
return ln;
}
typedef struct huff_code {
unsigned bitcode;
uchar bitcnt;
} huff_code;
typedef struct huff_icode {
uchar bitcode;
uchar bitcnt;
} huff_icode;
STATIC void swap_ptr(huff_tab **c1,huff_tab **c2);
STATIC int cmp_ptr (huff_tab **c1,huff_tab **c2);
STATIC void _fastcall addbit(huff_tab *cpt);
STATIC void _fastcall bit_write(register unsigned value,register int length);
STATIC uint _fastcall bit_read(register int length);
STATIC uint _fastcall huff_read(huff_icode *icode,int maxbit);
/**
*** generate Huffman codes for every character
**/
panic(char *s)
{
printf("%s\n",s);
exit(1);
}
STATIC void swap_ptr(huff_tab **c1,huff_tab **c2)
{
void *tmp;
tmp = *c1;
*c1 = *c2;
*c2 = tmp;
}
STATIC int cmp_ptr(huff_tab **c1,huff_tab **c2)
{
return (*c2)->count-(*c1)->count;
}
STATIC int current_max_bit;
STATIC void _fastcall addbit(register huff_tab *cpt)
{
while (cpt) {
addbit(cpt->lpt);
if (++cpt->bitcnt > current_max_bit)
longjmp(bit_to_long,1);
cpt = cpt->rpt; // faster then recursion
}
}
//**********************************************************************
// generate from huff_tab a field bitlength which holds the best bitlength
// for each character. allthough it would be possible to generate codes
// at the same time this has been avoided to make it easier usable when
// the data are read back
//**********************************************************************
STATIC int gen_length(uchar *bitlength,huff_tab *hufftab,
int charset,int maxbit)
{
PQ *pq;
huff_tab *cpt,*cpt1,*cpt2,*cpt3;
register int i;
long bsum;
int multiply ;
int anzcodes;
current_max_bit = maxbit; // we will not allow a longer table
// so the table is made more "flat"
if (setjmp(bit_to_long))
{
free(pq);
for (i=charset,cpt=hufftab;--i >= 0;cpt++)
{
if (cpt->count > 1)
cpt->count /= 2;
cpt->bitcnt = 0;
cpt->lpt = cpt->rpt = NULL;
}
multiply *= 2;
}
else
multiply = 1;
pq = pq_create(charset,sizeof(huff_tab*),cmp_ptr,swap_ptr,(void*)0);
for (anzcodes = 0,i=charset,cpt=hufftab;--i >= 0;cpt++)
if (cpt->count)
{
pq_ins(pq,&cpt);
anzcodes++;
}
if (anzcodes == 1) // the buffer is degenerated
{ // so we must set one code
pq_del(pq,&cpt1);
addbit(cpt1);
}
else {
cpt3 = hufftab+charset;
while(pq_del(pq,&cpt1) && pq_del(pq,&cpt2))
{
addbit(cpt1);
addbit(cpt2);
cpt3->lpt = cpt1;
cpt3->rpt = cpt2;
cpt3->bitcnt = cpt2->bitcnt;
cpt3->count= cpt1->count+cpt2->count;
pq_ins(pq,&cpt3);
cpt3++;
}
}
for (bsum = 0,i=charset,cpt=hufftab; i ;cpt++,--i)
{
bsum += cpt->bitcnt*cpt->count;
*bitlength++ = cpt->bitcnt;
}
free(pq);
return (int)((bsum+15)/8*multiply);
}
//**********************************************************************
// generate from huff_tab a field bitlength which holds the best bitlength
// for each character. allthough it would be possible to generate codes
// at the same time this has been avoided to make it easier usable when
// the data are read back
//**********************************************************************
STATIC int gen_code(huff_code *hufftab,uchar *bitlength,int charset)
{
register int loop,bitval,bitmask,first,lastcode,length;
for (loop = 0; loop < charset;loop++)
{
hufftab[loop].bitcnt = bitlength[loop];
hufftab[loop].bitcode = 0xffff;
}
lastcode = 0;
bitmask = 1;
first = 1;
for (length = 16; length >= 1; length--,bitmask <<= 1)
for (loop = 0; loop < charset;loop++)
{
if (hufftab[loop].bitcnt == length)
{
if (!first)
{
lastcode += bitmask;
}
first = 0;
hufftab[loop].bitcode = lastcode & ~(0xffff >> length);
}
}
}
STATIC gen_invtab(huff_icode *inv,huff_code *tab,int charset,int max_bit)
{
register int loop,ival,ianz,bitcnt;
for (loop = 0; loop < charset; loop++)
{
ival = tab[loop].bitcode >> (16-max_bit);
if ((bitcnt = tab[loop].bitcnt) == 0)
continue;
ianz = 1 << (max_bit-tab[loop].bitcnt);
for ( ; --ianz >= 0;ival++)
{
inv[ival].bitcode = loop;
inv[ival].bitcnt = bitcnt;
}
}
}
#define HIGH_BIT 16
unsigned short bit_value = 0;
unsigned short far *bit_ptr = NULL;
unsigned int bit_drin= 0;
#define dbrange(x) 0 // ((x) >= 0x1b0 && (x) <= 0x1d0)
STATIC void bit_flush(void)
{
if (bit_drin)
*bit_ptr++ = bit_value;
}
STATIC void bit_init(void far *ptr)
{
bit_ptr = ptr;
bit_drin = 0;
bit_value = 0;
}
STATIC void _fastcall bit_write(register unsigned value,register int length)
{
int fits = HIGH_BIT - bit_drin;
if (length <= fits)
{
*bit_ptr |= value >> bit_drin;
if (length == fits)
{
*bit_ptr++ = bit_value | (value >> bit_drin);
bit_drin = 0;
bit_value = 0;
}
else
{
bit_value |= value >> bit_drin;
bit_drin+=length;
}
}
else
{
*bit_ptr++ = bit_value | (value >> HIGH_BIT-fits);
bit_value = value <<= fits;
bit_drin = length-fits;
}
}
STATIC uint _fastcall bit_read(register int maxbit)
{
register unsigned value;
if (maxbit <= HIGH_BIT-bit_drin)
{
value = (*bit_ptr << bit_drin) >> (HIGH_BIT-maxbit);
}
else {
value = ((bit_ptr[0] << bit_drin) | (bit_ptr[1] >> (HIGH_BIT-bit_drin)))
>> (HIGH_BIT-maxbit);
}
if ((bit_drin += maxbit) >= HIGH_BIT)
bit_drin -= HIGH_BIT,bit_ptr++;
return value;
}
STATIC uint _fastcall huff_read(huff_icode *icode,int maxbit)
{
register int loop,value;unsigned int lmask,*lptr;
if (maxbit <= HIGH_BIT-bit_drin)
{
value = (*bit_ptr << bit_drin) >> (HIGH_BIT-maxbit);
}
else {
value = ((bit_ptr[0] << bit_drin) | (bit_ptr[1] >> (HIGH_BIT-bit_drin)))
>> (HIGH_BIT-maxbit);
}
if ((bit_drin += icode[value].bitcnt) >= HIGH_BIT)
bit_drin -= HIGH_BIT,bit_ptr++;
return icode[value].bitcode;
}
//****************************************************************************
// reading / writing characterset bitcounts
// 0) write no characterset at all
// 1) write number of characters (4 Bits) with number of bits (4 Bits) PKZIP
// 2) write for each character number of bits (4 Bits)
// 3) set bitval to 0;
// while (bitval < bitcnt) write (0x10,2)
// while (bitval > bitcnt) write (0x11,2)
// write (0,1)
// 4) if (bitval OK) write (0,1)
// else write (1,1),write (number of Bits,4)
//****************************************************************************
unsigned bit_write_method = 0;
int write_cnt0(register uchar *bitlength,int charset,uint test)
{
return 0;
}
int read_cnt0(register uchar *bitlength,int charset)
{
int mask,bits;
for (bits = 0,mask = 1;mask < charset ; mask <<= 1)
bits++;
memset(bitlength,bits,charset);
}
//****************************************************************************
int write_cnt1(register uchar *bitlength,int charset,uint test)
{
register int needed,loop,id;
for (id = 0,loop=0,needed=0; loop < charset;loop++,bitlength++)
{
if (bitlength[0] == bitlength[1] && id < 15 && loop < charset-1)
id++;
else
{
if (test) bit_write(((bitlength[0] << 4) | id) << 8,8);
id = 0;
needed++;
}
}
return needed;
}
read_cnt1(uchar *bitlength,int charset)
{
register int loop,id,val;
do {
id = bit_read(8);
val = id >> 4;
id &= 0x0f;
do {
*bitlength++ = val;
charset--;
} while (--id >= 0);
} while (charset > 0);
}
//****************************************************************************
int write_cnt2(register uchar *bitlength,int charset,uint test)
{
if (!test)
return charset/2;
do {
bit_write(*bitlength<<(HIGH_BIT-4),4); // 4 Bit
bitlength++;
} while (--charset);
}
int read_cnt2(register uchar *bitlength,int charset)
{
do {
*bitlength++ = bit_read(4); // 4 Bit
} while (--charset);
}
//****************************************************************************
int write_cnt3(register uchar *bitlength,int charset,uint test)
{
register int needed,loop,bitval;
for (bitval = 0,loop=0,needed=0; loop < charset;loop++,bitlength++)
{
while (bitval > bitlength[0])
{
bitval--,needed+=2;
if (test)
bit_write(0x01 << (HIGH_BIT-2),2);
}
while (bitval < bitlength[0])
{
bitval++,needed+=2;
if (test)
bit_write(0x00 << (HIGH_BIT-2),2);
}
if (test)
bit_write(0x1 << (HIGH_BIT-1),1);
needed++;
}
return (needed+7)/8;
}
int read_cnt3(register uchar *bitlength,int charset)
{
register int needed,loop,bitval;
for (bitval = 0; --charset >= 0;)
{
while (bit_read(1) == 0)
if (bit_read(1))
bitval--;
else
bitval++;
*bitlength++ = bitval;
}
}
//****************************************************************************
int write_cnt4(register uchar *bitlength,int charset,uint test)
{
register int needed,bitval;
for (bitval = 0,needed=0; --charset >= 0;bitlength++)
{
if (bitval != bitlength[0])
{
bitval = bitlength[0],needed+=5;
if (test)
{
bit_write(1 << (HIGH_BIT-1),1);
bit_write( bitlength[0] << (HIGH_BIT-4),4);
}
}
else
{
if (test)
bit_write(0 << (HIGH_BIT-1),1);
needed++;
}
}
return (needed+7)/8;
}
int read_cnt4(register uchar *bitlength,int charset)
{
register int bitval;
for (bitval = 0; --charset >= 0;bitlength++)
{
if (bit_read(1))
bitval = bit_read(4);
*bitlength = bitval;
}
}
//****************************************************************************
typedef int (*wrf)(register uchar *,int,uint);
typedef int (*rdf)(register uchar *,int);
wrf write_fun[] = { write_cnt0,write_cnt1,write_cnt2,write_cnt3,write_cnt4};
rdf read_fun[] = { read_cnt0, read_cnt1, read_cnt2, read_cnt3, read_cnt4};
test_wr_cnt(uchar *bitlength,int charset)
{
uint needed = 0xffff,len,method;
bit_write_method = 1;
for (method = 1;method < LENGTH(write_fun);method++)
{
len = (*write_fun[method])(bitlength,charset,FALSE);
if (len < needed)
bit_write_method = method,needed = len;
}
return needed;
}
//****************************************************************************
#define LITLEN 256 // characterset for literal characters
#define LENLEN 16 // characterset for length 0..15
#define INDLEN (4096 >> INDSHIFT) // characterset for index = (0..4096) >> 4
#define MASLEN 256 // characterset for packmask
#define EXTLEN 256 // characterset for extended length
#define INDSHIFT 4
#define INDMASK 0x0f
#define LIT_MAX 12 // MAXIMUM needed bits for each charset
#define IND_MAX 11
#define LEN_MAX 7
#define MAS_MAX 11
#define EXT_MAX 11
#define LIT_FLAG 0
#define IND_FLAG 3
#define LEN_FLAG 6
#define MAS_FLAG 9
#define EXT_FLAG 12
uint do_huff = 0;
uint huff_saved = 0;
hs_count(huff_tab *lit_tab,
huff_tab *len_tab,
huff_tab *ind_tab,
huff_tab *mas_tab,
huff_tab *ext_tab,uchar far *pbuffer,uint packlen)
{
register int uloop;
register uchar packmask;
int length;unsigned index;
for (uloop = 1;packlen > 0;packmask <<= 1)
{
if (--uloop == 0)
{
packmask = *pbuffer++,packlen--;
mas_tab[packmask].count++;
uloop = 8;
}
if ((packmask & 0x80) == 0) /* this byte is literally */
{
lit_tab[*pbuffer++].count++;
packlen--;
}
else
{ /* next 2 bytes coded */
index = *(int far *)pbuffer; /* 4 bit length */
length = (index >> 12);
ind_tab[(index & SENDLEN) >> INDSHIFT].count++;
len_tab[length].count++;
if (length == MAXCODELENGTH) /* length > 18 */
{ /* use next byte for length*/
ext_tab[pbuffer[2]].count++;
pbuffer += 3;
packlen -= 3;
}
else {
packlen -= 2;
pbuffer += 2;
}
}
}
}
#define HWRITE(x,tab) bit_write(tab[x].bitcode,tab[x].bitcnt)
hs_write(huff_code *lit_code,
huff_code *len_code,
huff_code *ind_code,
huff_code *mas_code,
huff_code *ext_code,uchar far *pbuffer,uint packlen)
{
register int uloop;
register uchar packmask;
int length;unsigned index;
for (uloop = 1;packlen > 0;packmask <<= 1)
{
if (--uloop == 0)
{
packmask = *pbuffer++,packlen--;
HWRITE(packmask,mas_code);
uloop = 8;
}
if ((packmask & 0x80) == 0) /* this byte is literally */
{
HWRITE(*pbuffer,lit_code);
pbuffer++;
packlen--;
}
else
{ /* next 2 bytes coded */
index = *(int far *)pbuffer; /* 4 bit length */
length = (index >> 12);
HWRITE(length,len_code);
index &= SENDLEN;
HWRITE(index >> INDSHIFT,ind_code);
bit_write((index&INDMASK) << (HIGH_BIT-INDSHIFT),INDSHIFT);
if (length == MAXCODELENGTH) /* length > 18 */
{ /* use next byte for length*/
HWRITE(pbuffer[2],ext_code);
pbuffer += 3;
packlen -= 3;
}
else {
pbuffer += 2;
packlen -= 2;
}
}
}
}
unsigned summup(register huff_tab *tab,uint charset)
{
uint sum = 0;
do {
sum += tab->count;
tab++;
} while (--charset);
return sum;
}
//
// check whether this code should be huffed
// do some (de)allocation at the same time
//
huff_code *hs_wr_code(huff_tab *tab,int charset,int maxbit,uint do_flag)
{
uchar *bitlength;
huff_code *code;
uint huff_len;
int needed,loop;
uint flatlen = ln2(charset); // number of bits in charset
uint maxlen = (uint)((long)summup(tab,charset) * flatlen / 8);
// used if stored flat
bitlength = ck_alloc(charset);
huff_len = gen_length(bitlength,tab,charset,maxbit);
needed = test_wr_cnt(bitlength,charset);
code = ck_alloc(charset*sizeof(huff_code));
if (needed + huff_len < maxlen)
{
huff_saved += maxlen - (needed + huff_len);
do_huff |= bit_write_method << do_flag;
(*write_fun[bit_write_method])(bitlength,charset,TRUE);
}
else
{
memset(bitlength,flatlen,charset); // generate flat characterset
}
gen_code(code,bitlength,charset);
free(bitlength);
free(tab);
return code;
}
hs_pack(uchar far *hbuffer,uint plen,uchar far *pbuffer,uint length)
{
huff_tab *lit_tab,*len_tab,*ind_tab,*mas_tab,*ext_tab;
huff_code *lit_code,*len_code,*ind_code,*mas_code,*ext_code;
uint huff_len;
register int loop;
memset(hbuffer,0,plen);
lit_tab = ck_alloc(LITLEN*2*sizeof(huff_tab));
ind_tab = ck_alloc(INDLEN*2*sizeof(huff_tab));
len_tab = ck_alloc(LENLEN*2*sizeof(huff_tab));
mas_tab = ck_alloc(MASLEN*2*sizeof(huff_tab));
ext_tab = ck_alloc(EXTLEN*2*sizeof(huff_tab));
hs_count(lit_tab,len_tab,ind_tab,mas_tab,ext_tab,pbuffer,length);
do_huff = 0;
huff_saved = 0;
bit_init(hbuffer+4);
lit_code = hs_wr_code(lit_tab,LITLEN,LIT_MAX,LIT_FLAG);
ind_code = hs_wr_code(ind_tab,INDLEN,IND_MAX,IND_FLAG);
len_code = hs_wr_code(len_tab,LENLEN,LEN_MAX,LEN_FLAG);
mas_code = hs_wr_code(mas_tab,MASLEN,MAS_MAX,MAS_FLAG);
ext_code = hs_wr_code(ext_tab,EXTLEN,EXT_MAX,EXT_FLAG);
if (do_huff == 0 ) // there is nothing to do
{
return 0xffff;
}
if (length - huff_saved + 6 >= plen) // or its not worth the effort
{
return 0xffff;
}
((short far *)hbuffer)[0] = do_huff;
((short far *)hbuffer)[1] = length;
hs_write(lit_code,len_code,ind_code,mas_code,ext_code,pbuffer,length);
free(lit_code);
free(ind_code);
free(len_code);
free(mas_code);
free(ext_code);
bit_flush();
return (uchar far *)bit_ptr - (uchar far *)pbuffer;
}
huff_icode *hs_rd_code(int charset,int maxbit,uint flatlen,int do_flag)
{
uchar *bitlength;
huff_code *code;
huff_icode *icode;
register int loop;
bitlength = ck_alloc(charset);
(*read_fun[(do_huff >> do_flag) & 0x07])(bitlength,charset);
code = ck_alloc(charset*sizeof(huff_code));
gen_code(code,bitlength,charset);
free(bitlength);
icode = ck_alloc((1<<maxbit)*sizeof(huff_icode));
gen_invtab(icode,code,charset,maxbit);
free(code);
return icode;
}
hs_unpack(uchar far *ubuffer,uchar far *hbuffer,uint packlen)
{
huff_icode *lit_icode,*len_icode,*ind_icode,*mas_icode,*ext_icode;
register int uloop;
register uchar packmask;
int length;unsigned index;
uchar far *sbuffer = ubuffer;
do_huff = ((short far *)hbuffer)[0];
packlen = ((short far *)hbuffer)[1];
bit_init(hbuffer+4);
lit_icode = hs_rd_code(LITLEN,LIT_MAX,8,LIT_FLAG);
ind_icode = hs_rd_code(INDLEN,IND_MAX,8,IND_FLAG);
len_icode = hs_rd_code(LENLEN,LEN_MAX,4,LEN_FLAG);
mas_icode = hs_rd_code(MASLEN,MAS_MAX,8,MAS_FLAG);
ext_icode = hs_rd_code(EXTLEN,EXT_MAX,8,EXT_FLAG);
for (uloop = 1;packlen > 0;packmask <<= 1)
{
if (--uloop == 0)
{
packmask = huff_read(mas_icode,MAS_MAX),packlen--;
uloop = 8;
}
if ((packmask & 0x80) == 0) /* this byte is literally */
{
*ubuffer++ = huff_read(lit_icode,LIT_MAX),packlen--;
}
else
{ /* next 2 bytes icoded */
length = huff_read(len_icode,LEN_MAX)+MIN_LENGTH;
index = huff_read(ind_icode,IND_MAX) << INDSHIFT;
index += bit_read(INDSHIFT);
if (length == MAXCODELENGTH+MIN_LENGTH) /* length > 18 */
{ /* use next byte for length*/
length = huff_read(ext_icode,EXT_MAX); /* icode is 3 bytes */
packlen -= 3;
}
else {
packlen -= 2;
}
/* copy BYTEWISE with OVERWRITE */
if (index == 1) // memcpy will not work as it copies WORDS
memset(ubuffer,*(ubuffer-1),length);
else
memcpy(ubuffer,ubuffer-index,length);
ubuffer += length;
}
}
free(lit_icode);
free(ind_icode);
free(len_icode);
free(mas_icode);
free(ext_icode);
return ubuffer-sbuffer;
}
#ifdef TEST
/**
**/
#define BSIZE 4096
#define CHARSET 256
unsigned char buffer[BSIZE];
unsigned char pbuffer[BSIZE];
unsigned char ubuffer[BSIZE];
main(int argc,char *argv[])
{
int fd;
uint loop,rd,code;
uint hufflen;
long inlen = 0,outlen = 0;
long time,ptime=0,utime=0;
if ((fd = open(argv[1],O_RDONLY|O_BINARY)) < 0)
return 1;
tx_init();
while ((rd = read(fd,buffer,BSIZE)) > 0)
{
inlen += rd;
mikro_diff();
hufflen = huff_pack(pbuffer,BSIZE,buffer,rd,CHARSET,12);
ptime += mikro_diff();
// printf("%5d --> %5d\n",rd,hufflen);
if (hufflen == 0xffff)
{
outlen += rd;
continue;
}
outlen += hufflen;
memset(pbuffer+hufflen,0xaa,3);
mikro_diff();
huff_unpack(ubuffer,pbuffer,rd,CHARSET,12);
utime += mikro_diff();
for (loop = 0; loop < rd; loop++)
if (buffer[loop] != ubuffer[loop])
{
char b[48];
printf("differenz at %04x\n",loop);
memcpy(b,buffer+loop-16,48);
hexdn(b,48);
printf("\n");
memcpy(b,ubuffer+loop-16,48);
hexdn (b,48);
exit(1);
}
}
printf("inlen %5ld --> outlen %5ld ptime %5ld utime %5ld",inlen,outlen,ptime,utime);
printf(" pack %5ld unpackc %5ld\n",
inlen*1000/ptime,
inlen*1000/utime
);
exit(0);
}
#endif